﻿// Copyright (c) 2010-2012, MatthiWare
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. 
// You shall include 'MatthiWare' in the credits/about section of the program
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//

using System;
using System.Collections.Generic;
using System.Text;
using SharpDX.DirectWrite;
using System.Diagnostics;
using OpenGameEngine.Base;
using System.Runtime.InteropServices;

namespace OpenGameEngine
{

    /// <summary>
    /// Specifies weights for font rendering.
    /// </summary>
    public enum FontWeight
    {
        /// <summary>
        /// Use a black weight.
        /// </summary>
        Black = 900,
        /// <summary>
        /// Use a bold weight.
        /// </summary>
        Bold = 700,
        /// <summary>
        /// Use a demi-bold weight.
        /// </summary>
        DemiBold = 600,
        /// <summary>
        /// The font weight doesn't matter.
        /// </summary>
        DoNotCare = 0,
        /// <summary>
        /// Use an extra bold weight.
        /// </summary>
        ExtraBold = 800,
        /// <summary>
        /// Make the font extra light.
        /// </summary>
        ExtraLight = 200,
        /// <summary>
        /// Use a heavy weight.
        /// </summary>
        Heavy = 900,
        /// <summary>
        /// Make the font light.
        /// </summary>
        Light = 300,
        /// <summary>
        /// Use a medium weight.
        /// </summary>
        Medium = 500,
        /// <summary>
        /// Use a normal weight.
        /// </summary>
        Normal = 400,
        /// <summary>
        /// Use a regular weight.
        /// </summary>
        Regular = 400,
        /// <summary>
        /// Use a semi-bold weight.
        /// </summary>
        SemiBold = 600,
        /// <summary>
        /// Make the font thin.
        /// </summary>
        Thin = 100,
        /// <summary>
        /// Use an ultra bold weight.
        /// </summary>
        UltraBold = 800,
        /// <summary>
        /// Make the font ultra light.
        /// </summary>
        UltraLight = 200
    }


    public enum FontStretch
    {
        Condensed = 3,
        Expanded = 7,
        ExtraCondensed = 2,
        ExtraExpanded = 8,
        Medium = 5,
        Normal = 5,
        SemiCondensed = 4,
        SemiExpanded = 6,
        UltraCondensed = 1,
        UltraExpanded = 9,
        Undefined = 0
    }

    public enum FontStyle
    {
        Italic,
        Normal,
        Oblique
    }

    public class Font
    {
        [DllImport("gdi32.dll")]
        private static extern int AddFontResourceEx(string lpszFilename, uint fl, IntPtr pdv);
        private const uint FR_PRIVATE = 0x10;
        private const uint FR_NOT_ENUM = 0x20;

        public FontStyle FontStyle { get; set; }
        public FontWeight FontWeight { get; set; }
        public String FontFamily { get; set; }
        public float FontSize { get; set; }
        public FontStretch FontStretch { get; set; }

        public Font(String fontName, float fontSize)
            : this(fontName, fontSize, FontStyle.Normal, FontWeight.Normal)
        {

        }

        public Font(String fontName, float fontSize, FontStyle style, FontWeight weight)
            : this(fontName, fontSize, style, weight, FontStretch.Normal)
        {

        }

        public Font(String fontName, float fontSize, FontStyle style, FontWeight weight, FontStretch fontStrecht)
        {
            FontFamily = fontName;
            FontSize = fontSize;
            FontStyle = style;
            FontWeight = weight;
            FontStretch = fontStrecht;
        }

        public static SizeF GetTextSize(String text, Font textFont)
        {
            TextLayout tl = MakeLayout(text, textFont);
            return new SizeF(tl.Metrics.Width, tl.Metrics.Height);
        }

        public static TextLayout MakeLayout(String text, Font font)
        {
            return new TextLayout(Globals.FactoryWrite, text, new TextFormat(Globals.FactoryWrite, font.FontFamily, ConvertFontWeight(font.FontWeight), ConvertFontStyle(font.FontStyle), font.FontSize), float.MaxValue, float.MaxValue);
        }

        public static TextLayout MakeLayout(String text, TextFormat textFormat)
        {
            return new TextLayout(Globals.FactoryWrite, text, textFormat, float.MaxValue, float.MaxValue);
        }

        public static TextFormat MakeFormat(Font font)
        {
            return new TextFormat(Globals.FactoryWrite, font.FontFamily, ConvertFontWeight(font.FontWeight), ConvertFontStyle(font.FontStyle), ConvertFontStretch(font.FontStretch), font.FontSize);
        }

        private static SharpDX.DirectWrite.FontWeight ConvertFontWeight(FontWeight sdxfw)
        {
            SharpDX.DirectWrite.FontWeight fw = SharpDX.DirectWrite.FontWeight.Normal;

            switch (sdxfw)
            {
                case FontWeight.Bold:
                    fw = SharpDX.DirectWrite.FontWeight.Bold;
                    break;
                case FontWeight.ExtraBold:
                    fw = SharpDX.DirectWrite.FontWeight.ExtraBold;
                    break;
                case FontWeight.ExtraLight:
                    fw = SharpDX.DirectWrite.FontWeight.ExtraLight;
                    break;
                case FontWeight.Heavy:
                    fw = SharpDX.DirectWrite.FontWeight.Heavy;
                    break;
                case FontWeight.Light:
                    fw = SharpDX.DirectWrite.FontWeight.Light;
                    break;
                case FontWeight.Medium:
                    fw = SharpDX.DirectWrite.FontWeight.Medium;
                    break;
                case FontWeight.Normal:
                    fw = SharpDX.DirectWrite.FontWeight.Normal;
                    break;
                case FontWeight.SemiBold:
                    fw = SharpDX.DirectWrite.FontWeight.SemiBold;
                    break;
                case FontWeight.Thin:
                    fw = SharpDX.DirectWrite.FontWeight.Thin;
                    break;
            }

            return fw;
        }

        private static SharpDX.DirectWrite.FontStyle ConvertFontStyle(FontStyle sdxfs)
        {
            SharpDX.DirectWrite.FontStyle fs = SharpDX.DirectWrite.FontStyle.Normal;

            switch (sdxfs)
            {
                case FontStyle.Italic:
                    fs = SharpDX.DirectWrite.FontStyle.Italic;
                    break;
                case FontStyle.Normal:
                    fs = SharpDX.DirectWrite.FontStyle.Normal;
                    break;
                case FontStyle.Oblique:
                    fs = SharpDX.DirectWrite.FontStyle.Oblique;
                    break;
            }

            return fs;
        }

        private static SharpDX.DirectWrite.FontStretch ConvertFontStretch(FontStretch sdxfs)
        {
            SharpDX.DirectWrite.FontStretch fs = SharpDX.DirectWrite.FontStretch.Normal;

            switch (sdxfs)
            {
                case FontStretch.Condensed:
                    fs = SharpDX.DirectWrite.FontStretch.Condensed;
                    break;
                case FontStretch.Expanded:
                    fs = SharpDX.DirectWrite.FontStretch.Expanded;
                    break;
                case FontStretch.ExtraCondensed:
                    fs = SharpDX.DirectWrite.FontStretch.ExtraCondensed;
                    break;
                case FontStretch.ExtraExpanded:
                    fs = SharpDX.DirectWrite.FontStretch.ExtraExpanded;
                    break;
                case FontStretch.Normal:
                    fs = SharpDX.DirectWrite.FontStretch.Normal;
                    break;
                case FontStretch.SemiCondensed:
                    fs = SharpDX.DirectWrite.FontStretch.SemiCondensed;
                    break;
                case FontStretch.SemiExpanded:
                    fs = SharpDX.DirectWrite.FontStretch.SemiExpanded;
                    break;
                case FontStretch.UltraCondensed:
                    fs = SharpDX.DirectWrite.FontStretch.UltraCondensed;
                    break;
                case FontStretch.UltraExpanded:
                    fs = SharpDX.DirectWrite.FontStretch.UltraExpanded;
                    break;
                case FontStretch.Undefined:
                    fs = SharpDX.DirectWrite.FontStretch.Undefined;
                    break;
            }

            return fs;
        }

        public static void InstallFont(String file)
        {
            if (String.IsNullOrEmpty(file))
                throw new ArgumentNullException("file", "The font file path cannot be empty!");

            if (!System.IO.File.Exists(file))
                throw new System.IO.FileNotFoundException("The font file is missing!", file);

            if (AddFontResourceEx(file, (FR_NOT_ENUM | FR_PRIVATE), IntPtr.Zero) == 0)
                throw new Exception("Unable to install font!");
        }
    }
}
